package com.atguigu.spzx.common.aspects;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.atguigu.spzx.common.annotations.Log;
import com.atguigu.spzx.common.service.SysOperLogService;
import com.atguigu.spzx.model.pojo.log.SysOperLog;
import com.atguigu.spzx.model.pojo.system.SysUserAuthContextUtil;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Arrays;
import java.util.Date;

/**
 * @author dyl
 * @version 1.0
 * @description:
 * @date 2025/1/16 16:37
 */
@Aspect
public class SysLogAspect {
    @Autowired
    private SysOperLogService sysOperLogService;

    // 切面 before after throw return around
    @Around(value = "@annotation(sysLog)")
    public Object logAspect(ProceedingJoinPoint joinPoint, Log sysLog) {
        Object proceed = null;
        SysOperLog sysOperLog = new SysOperLog();
        try {
            // 执行方法之前
            System.out.println("aspect 方法之前执行");
            beforeMethod(sysOperLog, joinPoint, sysLog);
            // 执行方法
            proceed = joinPoint.proceed();

            // 执行方法之后
            System.out.println("aspect 方法之后执行");
            afterMethod(sysOperLog, proceed,sysLog);

        } catch (Throwable e) {
            // 抛出异常后
            throwMethod(sysOperLog, sysLog, e);
//            sysOperLogService.insertLog(sysOperLog);
//            System.out.println("结果返回并保存日志");
            throw new RuntimeException(e);
        }
        finally {
            // 最后把结果返回并保存日志
            sysOperLogService.insertLog(sysOperLog);
            System.out.println("结果返回并保存日志");
//            return proceed;
        }
//        sysOperLogService.insertLog(sysOperLog);
//        System.out.println("结果返回并保存日志");
        return proceed;
    }

    // 执行方法之前的日志记录
    private void beforeMethod(SysOperLog sysOperLog, ProceedingJoinPoint joinPoint, Log sysLog) {
        // 获取request
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = sra.getRequest();

        sysOperLog.setTitle(sysLog.title());
        sysOperLog.setBusinessType(String.valueOf(sysLog.businessType()));


        // 通过反射获取方法名
        // 反射对象
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String name = signature.getMethod().getDeclaringClass().getName(); // 这个是类名
        String name1 = signature.getMethod().getName(); // 这个是方法名
        sysOperLog.setMethod(name);

        // 通过request获取请求方式
        sysOperLog.setRequestMethod(request.getMethod());

        // 操作人name  从本地线程中获取操作人
        sysOperLog.setOperName(SysUserAuthContextUtil.get().getName());
        sysOperLog.setOperatorType(sysLog.operatorType().toString());
        sysOperLog.setOperUrl(request.getRequestURL().toString());
        sysOperLog.setOperIp(request.getRemoteAddr());
        sysOperLog.setOperParam(Arrays.toString(joinPoint.getArgs()));
    }

    // 执行方法之后的日志记录
    private void afterMethod(SysOperLog sysOperLog, Object proceed, Log sysLog) {
        if (proceed != null){
            sysOperLog.setJsonResult(String.valueOf((JSONUtil.parse(proceed))));
        }
        sysOperLog.setStatus(0);
    }

    private void throwMethod(SysOperLog sysOperLog, Log sysLog, Throwable e) {
        sysOperLog.setStatus(1);
        sysOperLog.setErrorMsg(e.getMessage());
    }
}
